<template>
  <!-- 导出 -->
  <span>
    <a-button
      v-if="!custom"
      v-bind="$attrs"
      :type="buttonType"
      :icon="icon"
      :disabled="disabled"
      v-on="$listeners"
      :loading="downLoading"
      @click="handleClick"
      >{{ buttonText }}</a-button
    >
    <!-- 插槽 -->
    <slot v-else :downFile="downExcel" />
  </span>
</template>

<script>
import { Workbook } from 'exceljs'

export default {
  name: 'ExportExcel',
  props: {
    // 导出按钮文本
    buttonText: {
      type: String,
      default: () => '导出'
    },
    // 导出按钮图标
    icon: {
      type: String,
      default: () => 'cloud-download'
    },
    // 导出按钮类型
    buttonType: {
      type: String,
      default: () => 'primary'
    },
    // 自定义容器
    custom: {
      type: Boolean,
      default: () => false
    },
    // 禁用按钮
    disabled: {
      type: Boolean,
      default: () => false
    },
    // 导出列表配置项
    exportList: {
      type: Array,
      require: true
    },
    // 表头字段配置项
    columnsProps: {
      type: Object,
      default: () => ({
        header: 'title',
        key: 'dataIndex'
      })
    },
    // 导出文件名
    fileName: {
      type: String,
      default: () => 'test.xlsx'
    },
    // 导出之前回调，可以是同步方法，也可以是异步promise
    beforeDownload: {
      type: [Object, Function],
      default: () => null
    },
    // 导出之后回调
    afterDownload: {
      type: [Object, Function],
      default: () => null
    }
  },
  data() {
    return {
      downLoading: false
    }
  },
  methods: {
    /**
     * @description:点击事件
     */
    handleClick() {
      this.downLoading = true
      setTimeout(()=>{
        this.downLoading = false
      }, 1000)
      // 若有自定义点击则执行，否则直接导出
      if (this.$listeners['click']) {
        this.$emit('click')
        return
      }
      this.downExcel()
    },
    /**
     * @description: 下载excel
     */
    async downExcel() {
      // 导出前回调
      this.beforeDownload && (await this.beforeDownload())
      // 校验配置项
      if (!this.columnsProps || !this.columnsProps.header || !this.columnsProps.key) {
        this.$message.warning('表头配置项错误')
        return
      }

      this.$nextTick(async () => {
        const wb = new Workbook() // 文件簿实例
        try {
          // 根据导出配置初始化导出数据
          for (let index in this.exportList) {
            let item = this.exportList[index]
            let Sheet = wb.addWorksheet(item.title || `Sheet${Number(index + 1)}`) // 添加sheet表且命名

            item.columns = item.columns.filter((i) => i.header !== '操作' && !i.isHidden) // 筛选有效表头
            // 格式化表头
            item.columns?.forEach((i) => {
              i.header = i[this.columnsProps.header]
              i.key = i[this.columnsProps.key]
              i.width = i[this.columnsProps?.width] || 20
              if (i.header === '序号') {
                i.width = 10
                item.datas.forEach((e, num) => {
                  e[i.key] = Number(num) + 1
                })
              }
            })

            // 添加表头
            Sheet.columns = item.columns
            // 添加数据
            Sheet.addRows(item.datas)

            // 遍历选择项配置
            for (let index in item.columns) {
              let column = item.columns[index]
              let dataValidation = column.excelConfig?.dataValidation
              // 数据验证
              if (dataValidation && item.datas?.length > 0) {
                // 遍历数据表给每一行添加数据验证
                item.datas.forEach((_, idx) => {
                  let row = idx + 2 // 起始行，一般为第二行（表头下第一行）
                  // 给特定列的特定行添加选择器
                  if (dataValidation.type === 'list') {
                    dataValidation.formulae = [`"${column.options?.join()}"`]
                    for (let i = 0; i < 10000; i++) {
                      Sheet.getCell(i + 1, Number(index) + 1).dataValidation = column.excelConfig.dataValidation
                    }
                  } else {
                    // 数据验证
                    Sheet.getCell(row, Number(index) + 1).dataValidation = column.excelConfig.dataValidation
                  }
                })
              }
              // 表头设置
              Object.assign(Sheet.getCell(1, Number(index) + 1), column.excelConfig)
            }
            // return
          }
        } catch (err) {
          console.log(err)
          this.$message.warning('文件配置项错误')
          return
        }

        // 导出
        const buffer = await wb.xlsx.writeBuffer()

        let blob = new Blob([buffer], {
          type: 'application/octet-stream'
        })

        let url = blob
        let saveName = this.fileName

        if (url instanceof Object && url instanceof Blob) {
          url = URL.createObjectURL(url) // 创建blob地址
        }
        var aLink = document.createElement('a')
        aLink.href = url
        aLink.download = saveName || '' // 文件名
        let event
        if (window.MouseEvent) {
          event = new MouseEvent('click')
        } else {
          event = document.createEvent('MouseEvents')
          event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
        }
        aLink.dispatchEvent(event)
      })

      // 导出后回调
      this.afterDownload && this.afterDownload()
    }
  }
}
</script>
